/*
 * GenericSelectorDescription.java
 * 
 * last update: 01.02.2010 by Florea Mihai
 * 
 * author:	Alec(panovici@elcom.pub.ro)
 * 			Florea Mihai(florea.mihai@gmail.com)
 * 
 * Obs: Am adaugat @SuppressWarnings("serial"). 
 */

package engine;

/**
 * A selector for an unknown type of register. Used for late name resolving.
 * The corresponding instances are:
 * @see BitSelect @see IntSelector @see RealSelector
 */
@SuppressWarnings("serial")
class GenericSelectorDescription implements ExpressionDescription,
AssignableSelection{
	//combines the RealSelector, IntegerSelector

	FQNDescription fqn;
	ExpressionDescription start, end;

	/**
	 * true if start & end are valid.
	 */
	boolean hasLimits;

	/**
	 * true if this selector will be continuously assigned
	 */
	boolean tryContSelection;
	byte strength;

	/**
	 * The type-specific selector. Created at the first instantiation
	 * request, and used to make the other
	 * instantiations faster.
	 */
	ExpressionDescription theRealSelector;

	/**
	 * pre: (hasLimits = true && start != null && end != null)
	 *      ||  hasLimits = false
	 */
	GenericSelectorDescription (FQNDescription fqn,
			ExpressionDescription start,
			ExpressionDescription end, 
			boolean hasLimits) {
		this.fqn = fqn;
		this.start = start;
		this.end = end;
		this.hasLimits = hasLimits;
		tryContSelection = false;
	}

	GenericSelectorDescription (FQNDescription fqn) {
		this(fqn , null, null, false);
	}


	public Expression instantiate (NameSpace ns)
	throws ParseException
	{

		Object target = ns.resolveName(fqn.instantiate(ns));

		if (target == null)
			throw new ParseException("symbol \"" + fqn + "\" not found");

		if (target instanceof Register) {
			Register r = (Register)target;
			//TODO: pt asignarea registrilor trebuie umblat aici------------------------
			if (tryContSelection)
				throw new ParseException("Unimplemented: contassign for regs");

			if (hasLimits) {
				if(r.isMemory()) {
					if(tryContSelection)
						throw new ParseException("memory cannot be continuously assigned");
					if(start != end)
						throw new ParseException("part-select of a memory");
					Expression e = start.instantiate(ns);
					return new MemorySelector(ns, r, this,
							e,
							r.desc.getType() == Symbol.intType);
					/*          int nIndex;
          try {
            nIndex = (int) start.instantiate(ns).evaluate().getInt().value();
          } catch(UndefinedValueException ex) {
            throw new ParseException("invalid index in memory select:"
                                     + this + ": the value is not defined: ");
          } catch(InterpretTimeException ex) {
            xConsole.dumpStack(ex);
            throw new ParseException("invalid index in memory select:"
                                     + this + ": " + ex);
          }

          if(r.desc.getType() == Symbol.intType)
            return new IntSelector(ns, r.getData(nIndex), this);
          else
          return new BitSelect(ns, r.getData(nIndex), this);*/
				}else{ // !isMemory
					try {
						return new BitSelect(ns, r.getData(0), this,
								(int)
								start.instantiate(ns).evaluate().getLong(),
								(int)
								end.instantiate(ns).evaluate().getLong());
					} catch (InterpretTimeException itex) {
						throw new ParseException (itex.toString());
					}
				}
			}else{  // !hasLimits
				if(r.isMemory())
					throw new ParseException("missing index in memory select: "
							+ this);
				if((r.getType() & Symbol.regType) != 0) //unsigned (i.e. not int)
					return new BitSelect(ns, r.getData(0), this);
				else
					return new IntSelector(ns, r.getData(0), this); 
			}
		}

		if (target instanceof Real) {
			Real r = (Real)target;
			if(tryContSelection)
				throw new ParseException("real type cannot be continuously assigned");
			if(hasLimits)
				throw new ParseException("real " + fqn + " accessed at bit level");
			return new RealSelector(ns, r, this);
		}

		if (target instanceof Wire)
			try {
				Wire w = (Wire)target;
				xConsole.debug("selector: target is: " + w.desc + " cont: " +
						tryContSelection);
				if (tryContSelection)
					return  hasLimits ?
							new ContBitSelect(ns, w, this,
									(int) start.instantiate(ns).evaluate().getLong(),
									(int) end.instantiate(ns).evaluate().getLong(),
									strength) :
										new ContBitSelect(ns, w, this, strength);
							else return  hasLimits ?
									new BitSelect(ns, w, this,
											(int) start.instantiate(ns).evaluate().getLong(),
											(int) end.instantiate(ns).evaluate().getLong()) :
												new BitSelect(ns, w, this);
			} catch (InterpretTimeException itex) {
				throw new ParseException (itex.toString());
			}

			if (target instanceof Parameter) {
				Parameter p = (Parameter)target;
				if(tryContSelection)
					throw new ParseException("parameters cannot be contiuously assigned");

				return p;
			}

			throw new ParseException("symbol: \"" + fqn +
			"\" is not a register/wire/parameter/real");
	}

	public void toContSelection(byte strength)throws ParseException{
		this.strength = strength;
		tryContSelection = true;
	}

	public void toContSelection()throws ParseException{
		toContSelection(Strength.defaultStrength);
	}

	public String toString() {
		return fqn + ( start != null ? "[" + start +
				(end != null? ":" + end : "") + "]":"" );
	}
}


















